package com.csx.framework.netty.sample2;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.nio.charset.Charset;
import java.util.List;

/**
 * <p> what does this class do ? </p>
 *  自定义解码器
 * <p> How does it work ?</p>
 * <p> Why does it do this ?</p>
 *
 * @author cuisongxu
 * @date 2023/8/9 周三 11:18
 */
public class MyDecoder extends ByteToMessageDecoder {

    // 数据包基础长度
    private final int BASE_LENGTH = 4;


    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        // 基础长度不足,我们设定基础长度为4
        if(in.readableBytes() < BASE_LENGTH) {
            return;
        }

        int beginIdx; // 记录包头位置
        while(true) {

            // 获取包头开始的index
            beginIdx = in.readerIndex();
            // 标记包头开始的index
            in.markReaderIndex();
            // 读取到协议的开始标志,结束while循环
            if (in.readByte() == 0x02) {
                break;
            }

            // 未读到包头，略过一个字节
            in.resetReaderIndex();
            in.readByte();

            if (in.readableBytes() < BASE_LENGTH) {
                return;
            }
        }

        // 剩余长度不足可读数量[没有内容长度位]
        int readableCount = in.readableBytes();
        if(readableCount <= 1) {
            in.readerIndex(beginIdx);
            return;
        }

        // 长度域占4个字节，读取int
        ByteBuf byteBuf = in.readBytes(1);
        String msgLengthStr = byteBuf.toString(Charset.forName("GBK"));
        int msgLength = Integer.parseInt(msgLengthStr);

        // 剩余长度不足可读取数据[没有结尾标识]
        readableCount = in.readableBytes();
        if(readableCount < msgLength + 1) {
            in.readerIndex(beginIdx);
            return;
        }

        ByteBuf msgContent = in.readBytes(msgLength);

        // 如果没有结尾标识，还原指针位置(其他标识结尾)
        byte end = in.readByte();
        if(end != 0x03) {
            in.readerIndex(beginIdx);
            return;
        }

        out.add(msgContent.toString(Charset.forName("GBK")));

    }
}
